<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<bo>
</bo    dy>
</html>
<script>
    /*
    原始数据类型：直接存储在栈（stack）中，
                  占据空间小、大小固定，属于被频繁使用数据，所以放入栈中存储。
    引用数据类型：同时存储在栈（stack）和堆（heap）中，
                  占据空间大、大小不固定。
                  引用数据类型在栈中存储了指针，该指针指向堆中该实体的起始地址。
                  当解释器寻找引用值时，会首先检索其在栈中的地址，取得地址后从堆中获得实体。
    
    */
    /*
        js中数据类型的判断(typeof, 
                           indeanceof, 
                           constructor,
                           Obj.prototype.toString.call())
    */ 

    //type 引用检测基本数据类型(原始数据类型) 除了null都可以显示正确的类型 
    //type 对于对象来说 除函数以外都会显示object，所以说type并不能准确判断数据类型是什么。
    console.log(typeof 1);               // number
    console.log(typeof true);            // boolean
    console.log(typeof 'str');           // string
    console.log(typeof []);              // object     []数组的数据类型在 typeof 中被解释为 object
    console.log(typeof function(){});    // function
    console.log(typeof {});              // object
    console.log(typeof undefined);       // undefined
    console.log(typeof null);            // object     null 的数据类型被 typeof 解释为 object


    //instanceof 可以正确的判断对象的类型，因为内部机制是通过判断对象的原型链中是不是能找到类型的prototype  
    //a instanceof b 即b的原型链上是否存在a
    //直接字面量值判断数据类型 instanceof可以准确判断引用数据类型(Array,Function,Object)
    console.log([] instanceof Array);                    // true
    console.log(function(){} instanceof Function);       // true
    console.log({} instanceof Object);                   // true 
    //而基本数据类型不能被instanceof准确的判断
    console.log(1 instanceof Number);                    // false
    console.log(true instanceof Boolean);                // false 
    console.log('str' instanceof String);                // false    
    // console.log(undefined instanceof Undefined);
    // console.log(null instanceof Null);
    // MDN中instanceof运算符用来测试一个对象在其原型链中，是否存在一个构造函数的prototype属性
    // 其意思就是判断对象，是否是某一数据类型的实例，在这里字面量值，1， true ，'str'不是实例，所以判断值为false。


    //constructor
    console.log((1).constructor === Number);               // true
    console.log((true).constructor === Boolean);           // true
    console.log(('str').constructor === String);           // true
    console.log(([]).constructor === Array);               // true
    console.log((function() {}).constructor === Function); // true
    console.log(({}).constructor === Object);              // true
    //注意了，如果我创建一个对象，更改它的原型，constructor就会变得不可靠了
    function Fn(){};
    Fn.prototype=new Array();
    var f=new Fn();
    console.log(f.constructor===Fn);    // false
    console.log(f.constructor===Array); // true 
    

    //Object.prototype.toString.call() 使用Object对象的原型方法toString ，使用call改变指向，借用Object的toString方法
    var handleClass = Object.prototype.toString;
    console.log(handleClass.call(2));              //[object Number]
    console.log(handleClass.call(true));           //[object Boolean]
    console.log(handleClass.call('str'));          //[object String] 
    console.log(handleClass.call([]));             //[object Array]
    console.log(handleClass.call(function(){}));   //[object Function]
    console.log(handleClass.call({}));             //[object Object] 
    console.log(handleClass.call(undefined));      //[object Undefined] 
    console.log(handleClass.call(null));           //[object Null] 


</script>